package ch;

import org.omg.CORBA.INTERNAL;

import java.util.*;

/**
 * map实现的一致性hash
 *
 * @author yuh
 * @date 2018/4/26 15:18
 */
public class MapConsistentHash<T> implements ConsistentHash<T> {

    /**
     * 服务节点
     */
    private Map<Integer, SortedMap<Integer, T>> serverNodesIndex = new HashMap<>();
    /**
     * hash环
     */
    private SortedMap<Integer, String> slots = new TreeMap<>();

    /**
     * 虚拟节点个数
     */
    private static final int VIR_NODE = 5;


    /**
     * 加入一个元素
     *
     * @param key
     * @param val
     * @return 添加到服务器的索引
     */
    @Override
    public int add(String key, T val) {
        int hash = getHash(key);
        SortedMap<Integer, String> tailMap = slots.tailMap(hash);
        int realNodeIndex = getRealNodeIndex(hash);
        SortedMap<Integer, T> integerTSortedMap = serverNodesIndex.get(realNodeIndex);
        integerTSortedMap.put(hash, val);
        return realNodeIndex;
    }

    /**
     * 移除一个元素
     *
     * @param key
     * @return
     */
    @Override
    public T remove(String key) {

        return null;
    }

    /**
     * 添加服务器
     *
     * @param index  服务器的编号
     * @param server map模拟机器
     */
    @Override
    public void addServerNode(int index, SortedMap<Integer, T> server) {
        for (int i = 1; i <= VIR_NODE; i++) {
            String slot = String.format("%d#%d", index, i);
            int hash = getHash(slot);
            serverNodesIndex.put(index, server);
            slots.put(hash, slot);
            if (serverNodesIndex.size() == 1) {
                continue;
            }
            int realIndex = getRealNodeIndex(hash);
            moveElementsAccordHash(server, serverNodesIndex.get(realIndex), hash);
        }
    }


    /**
     * 移除一个服务器
     *
     * @param index 服务器的编号
     * @return
     */
    @Override
    public boolean removeServerNode(int index) {

        return true;
    }

    /**
     * 取出一个元素
     *
     * @param key
     * @return
     */
    @Override
    public T get(String key) {
        int hash = getHash(key);
        int realNodeIndex = getRealNodeIndex(hash);
        SortedMap<Integer, T> map = serverNodesIndex.get(realNodeIndex);
        return map.get(hash);
    }

    /**
     * 获取 |hashCode|
     *
     * @return
     */
    private int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash ^ str.charAt(i)) * p;
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;

        // 如果算出来的值为负数则取其绝对值
        if (hash < 0) {
            hash = Math.abs(hash);
        }
        return hash;
    }

    /**
     * 添加或者删除节点移除元素
     *
     * @param dest
     * @param src
     * @param hash
     */
    private void moveElementsAccordHash(Map<Integer, T> dest, Map<Integer, T> src, int hash) {
        if (src.isEmpty()) {
            return;
        }
        Set<Map.Entry<Integer, T>> entries = src.entrySet();
        LinkedList<Integer> removeIndex = new LinkedList<>();
        for (Map.Entry<Integer, T> entry : entries) {
            if (entry.getKey() < hash) {
                dest.put(entry.getKey(), entry.getValue());
                removeIndex.add(entry.getKey());
            }
        }
        for (Integer index : removeIndex) {
            src.remove(index);
        }
    }

    /**
     * 获得真实服务器
     *
     * @return
     */
    private int getRealNodeIndex(int hash) {
        String indexWithVir = "";
        SortedMap<Integer, String> tailMap = slots.tailMap(hash);
        if (tailMap == null || tailMap.size() == 0) {
            indexWithVir = slots.get(slots.firstKey());
        }
        indexWithVir = tailMap.get(tailMap.firstKey());
        String realNodeIndex = indexWithVir.split("#")[0];
        return Integer.parseInt(realNodeIndex);
    }
}
